﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Specialized;
using System.Net;

namespace GT
{
    public static partial class Extensions
    {

        #region GET methods

        public static void Get(this Uri url, object data, Action<byte[]> onSuccess, Action<HttpWebResponse> onFailure, Action<DownloadProgressChangedEventArgs> onProgress)
        {
            string param;
            if (data is NameValueCollection)
                param = (data as NameValueCollection).ToQueryString();
            else if (data is string)
                param = (data as string);
            else if (data.GetType().IsValueType)
                param = data.ToString().UrlEncode();
            else
                param = data.ToNameValueCollection().ToQueryString();

            WebClientEx wc = new WebClientEx();
            wc.DownloadProgressChanged += (src, ev) =>
                {
                    if (onProgress != null)
                        onProgress(ev);
                };
            wc.DownloadDataCompleted += (src, ev) =>
                {
                    if (ev.Error != null && onFailure != null)
                        onFailure(wc.Response);
                    else
                    {
                        if (onSuccess != null)
                            onSuccess(ev.Result);
                    }
                };

            string urlstr = url.ToString();
            if (urlstr.Contains("?"))
                urlstr = urlstr.Substring(0, urlstr.IndexOf("?"));
            Uri newUrl = new Uri(urlstr + "?" + param);

            wc.DownloadDataAsync(newUrl);
        }

        public static HttpWebResponse Get(this Uri url, object data, Action<byte[]> onSuccess, Action<HttpWebResponse> onFailure)
        {
            //url.Get(data, onSuccess, onFailure, null);

            string param;
            if (data is NameValueCollection)
                param = (data as NameValueCollection).ToQueryString();
            else if (data is string)
                param = (data as string);
            else if (data.GetType().IsValueType)
                param = data.ToString().UrlEncode();
            else
                param = data.ToNameValueCollection().ToQueryString();

            string urlstr = url.ToString();
            if (urlstr.Contains("?"))
                urlstr = urlstr.Substring(0, urlstr.IndexOf("?"));
            Uri newUrl = new Uri(urlstr + "?" + param);

            byte[] ret;
            HttpWebResponse response;
            using (WebClientEx wc = new WebClientEx())
            {
                try
                {
                    ret = wc.DownloadData(newUrl);
                    response = wc.Response;
                    if (onSuccess != null)
                        onSuccess(ret);
                }
                catch (WebException ex)
                {
                    ret = null;
                    response = ex.Response as HttpWebResponse;
                    if (onFailure != null)
                        onFailure(response);
                }
            }
            return response;
        }

        public static HttpWebResponse Get(this Uri url, object data, Action<byte[]> onSuccess)
        {
            return url.Get(data, onSuccess, null);
        }

        public static byte[] Get(this Uri url, object data)
        {
            string param;
            if (data is NameValueCollection)
                param = (data as NameValueCollection).ToQueryString();
            else if (data is string)
                param = (data as string);
            else if (data.GetType().IsValueType)
                param = data.ToString().UrlEncode();
            else
                param = data.ToNameValueCollection().ToQueryString();

            string urlstr = url.ToString();
            if (urlstr.Contains("?"))
                urlstr = urlstr.Substring(0, urlstr.IndexOf("?"));
            Uri newUrl = new Uri(urlstr + "?" + param);

            byte[] ret;
            using (WebClientEx wc = new WebClientEx())
            {
                try
                {
                    ret = wc.DownloadData(newUrl);
                }
                catch (WebException)
                {
                    ret = null;
                }
            }
            return ret;
        }

        public static byte[] Get(this Uri url)
        {
            WebClientEx wc = new WebClientEx();
            try
            {
                byte[] ret = wc.DownloadData(url);
                wc.Dispose();
                return ret;
            }
            catch (WebException)
            {
                wc.Dispose();
                return null;
            }
        }

        public static void Get(this Uri url, Action<byte[]> onSuccess, Action<HttpWebResponse> onFailure, Action<DownloadProgressChangedEventArgs> onProgress)
        {
            WebClientEx wc = new WebClientEx();
            wc.DownloadProgressChanged += (src, ev) =>
            {
                if (onProgress != null)
                    onProgress(ev);
            };
            wc.DownloadDataCompleted += (src, ev) =>
            {
                if (ev.Error != null && onFailure != null)
                {
                    if (ev.Error is WebException)
                        onFailure((ev.Error as WebException).Response as HttpWebResponse);
                    else
                        onFailure(wc.Response);
                }
                else
                {
                    if (onSuccess != null)
                        onSuccess(ev.Result);
                }
            };

            wc.DownloadDataAsync(url);
        }

        public static HttpWebResponse Get(this Uri url, Action<byte[]> onSuccess, Action<HttpWebResponse> onFailure)
        {
            HttpWebResponse response;
            using (WebClientEx wc = new WebClientEx())
            {
                try
                {
                    byte[] data = wc.DownloadData(url);
                    response = wc.Response;
                    if (onSuccess != null)
                        onSuccess(data);
                }
                catch (WebException ex)
                {
                    response = ex.Response as HttpWebResponse;
                    if (onFailure != null)
                        onFailure(ex.Response as HttpWebResponse);
                }
            }
            return response;
        }

        public static void Get(this Uri url, Action<byte[]> onSuccess)
        {
            url.Get(onSuccess, null);
        }

        #endregion

        #region POST methods

        public static void Post(this Uri url, object data, Action<byte[]> onSuccess, Action<HttpWebResponse> onFailure, Action<UploadProgressChangedEventArgs> onProgress)
        {
            byte[] param;
            if (data is NameValueCollection)
                param = Encoding.UTF8.GetBytes((data as NameValueCollection).ToQueryString());
            else if (data is string)
                param = Encoding.UTF8.GetBytes(data as string);
            else if (data is byte[])
                param = (data as byte[]);
            else if (data.GetType().IsValueType)
                param = Encoding.UTF8.GetBytes(data.ToString().UrlEncode());
            else
                param = Encoding.UTF8.GetBytes(data.ToNameValueCollection().ToQueryString());

            WebClientEx wc = new WebClientEx();
            wc.UploadProgressChanged += (src, ev) =>
            {
                if (onProgress != null)
                    onProgress(ev);
            };
            wc.UploadDataCompleted += (src, ev) =>
            {
                if (ev.Error != null && onFailure != null)
                {
                    if (ev.Error is WebException)
                        onFailure((ev.Error as WebException).Response as HttpWebResponse);
                    else
                        onFailure(wc.Response);
                }
                else
                {
                    if (onSuccess != null)
                        onSuccess(ev.Result);
                }
            };

            wc.UploadDataAsync(url, "POST", param);
        }

        public static HttpWebResponse Post(this Uri url, object data, Action<byte[]> onSuccess, Action<HttpWebResponse> onFailure)
        {
            HttpWebResponse response;
            byte[] param;
            if (data is NameValueCollection)
                param = Encoding.UTF8.GetBytes((data as NameValueCollection).ToQueryString());
            else if (data is string)
                param = Encoding.UTF8.GetBytes(data as string);
            else if (data is byte[])
                param = (data as byte[]);
            else if (data.GetType().IsValueType)
                param = Encoding.UTF8.GetBytes(data.ToString().UrlEncode());
            else
                param = Encoding.UTF8.GetBytes(data.ToNameValueCollection().ToQueryString());

            WebClientEx wc = new WebClientEx();
            try
            {
                byte[] ret = wc.UploadData(url, "POST", param);
                response = wc.Response;
                if (onSuccess != null)
                    onSuccess(ret);
            }
            catch (WebException ex)
            {
                response = ex.Response as HttpWebResponse;
                if (onFailure != null)
                    onFailure(ex.Response as HttpWebResponse);
            }
            finally
            {
                wc.Dispose();
            }
            return response;
        }

        public static HttpWebResponse Post(this Uri url, object data, Action<byte[]> onSuccess)
        {
            return url.Post(data, onSuccess, null);
        }

        public static byte[] Post(this Uri url, object data)
        {
            byte[] param;
            if (data is NameValueCollection)
                param = Encoding.UTF8.GetBytes((data as NameValueCollection).ToQueryString());
            else if (data is string)
                param = Encoding.UTF8.GetBytes(data as string);
            else if (data is byte[])
                param = (data as byte[]);
            else if (data.GetType().IsValueType)
                param = Encoding.UTF8.GetBytes(data.ToString().UrlEncode());
            else
                param = Encoding.UTF8.GetBytes(data.ToNameValueCollection().ToQueryString());

            WebClientEx wc = new WebClientEx();
            try
            {
                byte[] ret = wc.UploadData(url, "POST", param);
                wc.Dispose();
                return ret;
            }
            catch (WebException)
            {
                wc.Dispose();
                return null;
            }
        }

        #endregion
    }
}
